<?php
if ( file_exists( __DIR__ . '/config.inc.php' ) ) {
	require( __DIR__ . '/config.inc.php' );
} else {
	require( __DIR__ . '/sample-config.inc.php' );
}
require( dirname( __DIR__ ) . '/vendor/autoload.php' );

/**
 * Gets installation homepage URL.
 *
 * @return str
 */
function get_base_url() {
	global $config;
	if ( ! isset( $config['base_url'] ) ) {
		$base_url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
		$base_url .= dirname( $_SERVER['SCRIPT_NAME'] );
		return $base_url;
	} else {
		return $config['base_url'];
	}
}

/**
 * Returns a changed YT URL to work on local install.
 *
 * @param str $id Video/channel ID.
 * @param str $type Type of ID provided or URL to be generated. (video|channel)
 * @param array $extra_data Extra information to be included in the URL.
 * @return str
 */
function get_local_url( $id, $type = 'video', $extra_data = null ) {
	if ( $type == 'video' ) {
		return get_base_url() . '/watch?v=' . $id;
	} elseif ( $type == 'channel' ) {
		return get_base_url() . '/channel/' . $id;
	}
}

/**
 * Replaces all occurrences of YT urls from a string.
 *
 * @param str $input_string String to process.
 * @return str
 */
function replace_urls_with_local_urls( $input_string ) {
	$base_url = get_base_url();
	$patterns = array(
		// https://www.youtube.com/watch?v=C0DPdy98e4c&feature=feedrec_grec_index
		'/https*:\/\/(www.)*youtube.com\/watch(.*)v=([a-zA-Z0-9]*)/i',
		// http://youtu.be/C0DPdy98e4c
		'/https*:\/\/youtu.be\/([a-zA-Z0-9]*)/i',
		// https://www.youtube.com/embed/C0DPdy98e4c?rel=0
		'/https*:\/\/(www.)*youtube.com\/embed\/([a-zA-Z0-9]*)/i',
		// https://www.youtube.com/user/SomeUser_Name#p/a/u/1/QdK8U-VIH_o
		'/https*:\/\/(www.)*youtube.com\/user\/([a-zA-Z0-9_-]*)/i',
		// https://youtube.com/channel/UCHDm-DKoMyJxKVgwGmuTaQA
		'/https*:\/\/(www.)*youtube.com\/channel\/([a-zA-Z0-9_-]*)/i',
	);
	$replacements = array(
		"$base_url/watch?v=$3",
		"$base_url/watch?v=$1",
		"$base_url/watch?v=$2",
		"$base_url/user/$2",
		"$base_url/channel/$2",
	);
	return preg_replace( $patterns, $replacements, $input_string );
}

/**
 * Convert urls in the string into clickable links.
 *
 * @source https://stackoverflow.com/a/34732417
 *
 * @param str $input_string Input string to convert.
 * @return str
 */
function urlify_string( $input_string ) {
	return preg_replace( '/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]*(\/\S*)?/', '<a href="$0">$0</a>', $input_string );
}

/**
 * Returns a YT thumbnail image from a given video id
 *
 * @source https://stackoverflow.com/a/20542029
 *
 * @param str $video_id Video id to get the thumbnail for.
 * @param str $size Size of the thumbnail image to get url for. (small|medium|high)
 * @return str
 */
function get_video_thumbnail_url( $video_id, $size = 'medium' ) {
	if ( $size == 'small') {
		return "https://i.ytimg.com/vi/{$video_id}/default.jpg";
	} elseif ( $size == 'medium') {
		return "https://i.ytimg.com/vi/{$video_id}/mqdefault.jpg";
	} elseif ( $size == 'high') {
		return "https://i.ytimg.com/vi/{$video_id}/hqdefault.jpg";
	}
}

/**
 * Returns proxy-enabled url for proxy (esp. for frontend).
 */
// TODO: Implement proxy code and use throughout project.
function proxify_url( $url ) {
	return get_base_url() . '/proxyasset.php?url=' . urlencode( $url );
}

/**
 * Gets the content of an URL.
 *
 * @param str $url The URL to get contents of.
 * @return str
 */
function get_url_contents( $url ) {
	global $config;

	$ch = curl_init();
	$curl_options = array(
		CURLOPT_URL => $url,
		CURLOPT_FOLLOWLOCATION => 1,
		CURLOPT_RETURNTRANSFER => 1,
	);
	if ( $config['proxy_enabled'] ) {
		$curl_options[CURLOPT_PROXY] = "{$config['proxy_ip']}:{$config['proxy_port']}";
		if ( isset( $config['proxy_username'] ) ) {
			$curl_options[CURLOPT_PROXYUSERPWD] = "{$config['proxy_username']}:{$config['proxy_password']}";
		}
		switch( $config['proxy_type'] ) {
			case 'socks4':
				$curl_proxy_type = CURLPROXY_SOCKS4;
				break;
			case 'socks5':
				$curl_proxy_type = CURLPROXY_SOCKS5;
				break;
			case 'socks4a':
				$curl_proxy_type = CURLPROXY_SOCKS4A;
				break;
			default:
				$curl_proxy_type = CURLPROXY_HTTP;
		}
		$curl_options[CURLOPT_PROXYTYPE] = CURLPROXY_SOCKS5;
	}
	curl_setopt_array( $ch, $curl_options );
	$curl_output = curl_exec( $ch );
	curl_close( $ch );

	return $curl_output;
}

/**
 * Extracts json information from YT HTML.
 *
 * @param str $html Input HTML.
 * @return str|bool
 */
function get_initial_data( $html ) {
	if ( preg_match( '/window\["ytInitialData"\]\s*=\s*(?<info>.*?);+\n/i', $html, $matches ) ) {
		$json = $matches[1];
		$json = json_decode( $json );
		return $json;
	} else {
		return false;
	}
}

/**
 * Extracts items from extracted json (e.g. from get_initial_data()).
 *
 * @param str $json JSON string to be processed.
 * @return array
 */
function extract_items( $json ) {
	// Temporary storage variable for json data in array
	$items_json = array();
	// Return array
	$items = array();
	// Search data
	if ( isset( $json->contents->twoColumnSearchResultsRenderer ) ) {
		$items_json = @$json->contents->twoColumnSearchResultsRenderer->primaryContents->sectionListRenderer->contents[0]->itemSectionRenderer->contents;
	// Go through contents inside sub-arrays (for trending data etc.)
	// Path: @$json->contents->twoColumnBrowseResultsRenderer->tabs[0]->tabRenderer->content->sectionListRenderer->contents[0]->itemSectionRenderer->contents[0]->shelfRenderer->content->expandedShelfContentsRenderer->items;
	} elseif ( isset( $json->contents->twoColumnBrowseResultsRenderer ) ) {
		foreach ( @$json->contents->twoColumnBrowseResultsRenderer->tabs[0]->tabRenderer->content->sectionListRenderer->contents as $key => $sub_items ) {
			$nested_items = @$sub_items->itemSectionRenderer->contents[0]->shelfRenderer->content->expandedShelfContentsRenderer->items;
			if ( ! empty($nested_items) ) {
				$items_json = array_merge( $items_json, $nested_items );
			}
		}
	// Channel playlist (and also playlist??)
	} elseif ( isset( $json->contents->twoColumnWatchNextResults ) ) {
		//$items_json = @$json->contents->twoColumnWatchNextResults->results->results->contents; // not used
		$items_json = @$json->contents->twoColumnWatchNextResults->playlist->playlist->contents;
	}
	if ( ! empty( $items_json ) ) {
		foreach ( $items_json as $index => $item ) {
			$first_key = @array_keys( get_object_vars($item) )[0];

			if ( isset( $item->videoRenderer ) ) {
				$items[] = array(
					'item_type' => 'video',
					'video_id' => $item->videoRenderer->videoId,
					'video_url' => get_local_url( $item->videoRenderer->videoId, 'video' ),
					'thumbnail_url' => $item->videoRenderer->thumbnail->thumbnails[1]->url,
					'title' => $item->videoRenderer->title->runs[0]->text,
					'title_a11y' => $item->videoRenderer->title->accessibility->accessibilityData->label,
					'description' => $item->videoRenderer->descriptionSnippet->runs[0]->text . $item->videoRenderer->descriptionSnippet->runs[2]->text,
					'length' => $item->videoRenderer->lengthText->simpleText,
					'author_name' => $item->videoRenderer->ownerText->runs[0]->text,
					'author_url' => get_base_url() . $item->videoRenderer->ownerText->runs[0]->navigationEndpoint->browseEndpoint->canonicalBaseUrl,
					'channel_id' => get_base_url() . $item->videoRenderer->ownerText->runs[0]->navigationEndpoint->browseEndpoint->browseId,
					'views_text' => $item->videoRenderer->shortViewCountText->simpleText,
				);
			} elseif ( isset( $item->playlistPanelVideoRenderer ) ) {
				$video_id = @$item->{$first_key}->videoId;
				$items[] = array(
					'item_type' => 'video',
					'video_id' => $video_id,
					'video_url' => get_local_url( $video_id, 'video' ),
					'thumbnail_url' => $item->{$first_key}->thumbnail->thumbnails[1]->url,
					'title' => $item->{$first_key}->title->simpleText,
					'title_a11y' => $item->{$first_key}->title->accessibility->accessibilityData->label,
					'length' => $item->{$first_key}->lengthText->simpleText,
					'key_test' => $first_key,
				);

			} elseif ( isset( $item->channelRenderer ) ) {
				$items[] = array(
					'item_type' => 'channel',
					'channel_name' => $item->channelRenderer->title->simpleText,
					'channel_id' => $item->channelRenderer->channelId,
					'channel_url' => get_local_url( $item->channelRenderer->channelId, 'channel' ),
					'channel_thumbnail_url' => $item->channelRenderer->thumbnail->thumbnails[1]->url,
					'subscriber_count' => $item->channelRenderer->subscriberCountText->simpleText,
					'auto_generated' => ( isset( $item->channelRenderer->videoCountText ) ) ? false : true,
					'video_count' => $item->channelRenderer->videoCountText->runs[0]->text,
					'description' => $item->channelRenderer->descriptionSnippet,
				);
			// TODO: Process more types such as playlists etc. (https://github.com/iv-org/invidious/blob/db83ede73ca38cd4c661e96b8f9823db99d9f5c2/src/invidious/helpers/helpers.cr#L250)
			}
		}
	} else {
		throw new Exception( 'Contents node not found on extracted JSON' );
	}
	return $items;
}

/**
 * Friendly display of date and time (e.g. 1 month ago).
 *
 * @source https://stackoverflow.com/a/38897003
 *
 * @param int $time_ago The time passed as input.
 * @return str
 */
function time_ago( $time_ago ) {
    $time_ago = strtotime( $time_ago ) ? strtotime( $time_ago ) : $time_ago;
    $time  = time() - $time_ago;

    switch( $time ):
        // seconds
        case $time <= 60;
        return 'less than a minute ago';
        // minutes
        case $time >= 60 && $time < 3600;
        return (round($time/60) == 1) ? 'a minute' : round($time/60) . ' minutes ago';
        // hours
        case $time >= 3600 && $time < 86400;
        return (round($time/3600) == 1) ? 'an hour ago' : round($time/3600) . ' hours ago';
        // days
        case $time >= 86400 && $time < 604800;
        return (round($time/86400) == 1) ? 'a day ago' : round($time/86400) . ' days ago';
        // weeks
        case $time >= 604800 && $time < 2600640;
        return (round($time/604800) == 1) ? 'a week ago' : round($time/604800) . ' weeks ago';
        // months
        case $time >= 2600640 && $time < 31207680;
        return (round($time/2600640) == 1) ? 'a month ago' : round($time/2600640) . ' months ago';
        // years
        case $time >= 31207680;
        return (round($time/31207680) == 1) ? 'a year ago' : round($time/31207680) . ' years ago' ;
    endswitch;
}
